/* 
* createStore(reducer, preloadState, enhancer/强化)
* {
    getState,
    dispatch,
    subscribe //添加订阅者 状态更改 触发订阅
}
*/

function createStore(reducer, preloadState, enhancer){

    //增强store
    if(typeof enhancer == 'function'){
        //如果有增强函数 通过createStore 返回原始store enhancer内部函数对原始store增强 直接返回增强store 
        return enhancer(createStore)(reducer, preloadState)
    }
    //原始store
    let currentState = preloadState
    let listenerLists = []
    function getState(){
        return currentState
    }
    function dispatch(action){
        currentState = reducer(currentState, action)
        listenerLists.forEach(function(listener){
            listener()
        })
    }
    function subscribe(listener){
        listenerLists.push(listener)
    }
    return {
        getState,
        dispatch,
        subscribe
    }
}
//不用applyMiddleware 直接实现类似redux-thunk的enhancer
function enhancer(createStore){
    return (reducer, preloadState) => {
        const store = createStore(reducer, preloadState)
        const dispatch = store.dispatch
        const _dispatch = (action) => {
            if(typeof action === 'function'){
                return action(dispatch)
            }
            dispatch(action)
        }
        return {
            ...store,
            dispatch: _dispatch
        }
    }
}

/* 
* applyMiddleware
* applyMiddleware最终返回的应该是类似上方enhancer函数的结构 
* 中间件其实就是对原始store的dsipatch增强
* applyMiddleware增强dispatch 让其能对多个中间件按顺序执行 store => next => action => next(action)
* next 实际就是下一个中间件函数 当没有下一个中间件函数时 next就是dispatch方法
* store参数时阉割版 只需getState方法和dispatch方法
*/

function applyMiddleware(...middlewares){
    return createStore => {
        return (reducer, preloadState) => {
            const store = createStore(reducer, preloadState)
            const middlewareAPI = {
                getState: store.getState,
                dispatch: store.dispatch
            }
            //chain[next => action => next(action)]
            const chain = middlewares.map(middleware => middleware(middlewareAPI))
            const dispatch = chain.reverse().reduce((total,fn) => {
                return fn(total)
            }, store.dispatch)
            return {
                ...store,
                dispatch
            }
        }
    }
}

/* 
* bindActionCreators
* params: {
    increment: () => { type: 'increment' }
}
* return {
    increment: () => dispatch({ type: 'increment' })
}
*/
function bindActionCreators(actionCreators, dispatch){
    const boundActionCreators = {}
    for(let key in actionCreators){
        boundActionCreators[key] = () => dispatch(actionCreators[key]())
    } 
    return boundActionCreators
}

/* 
* combineReducers
* params {
    carts: cartsReducer
}
* return reducer
*/
function combineReducers(reducers){
    var reducerKeys = Object.keys(reducers)
    return (state, action) => {
        const nextState = {}
        reducerKeys.forEach(reducer => {
            nextState[key] = () => reducer(state[key], action)
        })
        return nextState
    }
}